home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / snd_amiga.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  14KB  |  437 lines

  1. /*
  2. Copyright (C) 2000 Peter McGavin.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // snd_amiga.c
  21.  
  22. #include <exec/exec.h>
  23. #include <dos/dos.h>
  24. #include <graphics/gfxbase.h>
  25. #include <devices/audio.h>
  26. #include <devices/ahi.h>
  27.  
  28. extern struct GfxBase *GfxBase;
  29.  
  30. #include <clib/alib_protos.h>
  31. #include <powerup/ppcproto/exec.h>
  32. #include <powerup/ppcproto/dos.h>
  33. #include <powerup/ppcproto/graphics.h>
  34. #include <powerup/ppcproto/ahi.h>
  35.  
  36. #include "quakedef.h"
  37.  
  38. /**********************************************************************/
  39.  
  40. extern int desired_speed;
  41. extern int desired_bits;
  42. int using_ahi = FALSE;
  43.  
  44. /**********************************************************************/
  45.  
  46. /* AHI */
  47.  
  48. #define AHIBUFFERSIZE 262144
  49.  
  50. struct ahi_channel_info {
  51.   struct AHIRequest *AHIio;
  52.   double starttime;
  53.   BOOL sound_in_progress;
  54. };
  55.  
  56. struct Library *AHIBase = NULL;
  57. static struct MsgPort *AHImp = NULL;
  58. static struct ahi_channel_info ahi_channel_info[2] = {
  59.   {NULL, 0.0, FALSE},
  60.   {NULL, 0.0, FALSE}
  61. };
  62. static BYTE AHIDevice = -1;
  63. static BOOL ahidevice_is_open = FALSE;
  64. static double ahi_playtime;
  65. static int which_buffer;
  66.  
  67.  
  68. /* audio.device */
  69.  
  70. /* #define BUFFERSIZE 16384 */
  71. #define BUFFERSIZE 4096
  72.  
  73. #define MAXNUMCHANNELS   4   /* max number of Amiga sound channels */
  74.  
  75. struct channel_info {
  76.   struct MsgPort *audio_mp;
  77.   struct IOAudio *audio_io;
  78.   double starttime;
  79.   BOOL sound_in_progress;
  80. };
  81.  
  82. static struct channel_info channel_info[MAXNUMCHANNELS] = {
  83.   {NULL, NULL, 0.0, FALSE},
  84.   {NULL, NULL, 0.0, FALSE},
  85.   {NULL, NULL, 0.0, FALSE},
  86.   {NULL, NULL, 0.0, FALSE},
  87. };
  88.  
  89. static int size;
  90. static struct MsgPort *audio_mp = NULL;
  91. static struct IOAudio *audio_io = NULL;
  92. static BOOL audio_is_open = FALSE;
  93. static ULONG clock_constant;   /* see Amiga Hardware Manual page 141 */
  94. static UWORD period;
  95. static double twice_real_speed;
  96.  
  97. /**********************************************************************/
  98. static void stop_ahi_sound (struct ahi_channel_info *c)
  99. {
  100.   if (!ahidevice_is_open)
  101.     return;
  102.   if (c->sound_in_progress) {
  103.     AbortIO ((struct IORequest *)c->AHIio);
  104.     WaitPort (AHImp);
  105.     GetMsg (AHImp);
  106.     c->sound_in_progress = FALSE;
  107.   }
  108. }
  109.  
  110. /**********************************************************************/
  111. // Starts an AHI sound in a particular sound channel.
  112. // Use link for double-buffering.
  113.  
  114. static void start_ahi_sound (struct ahi_channel_info *c,
  115.                              char *buffer, int length,
  116.                              struct AHIRequest *link)
  117. {
  118.   if (!ahidevice_is_open)
  119.     return;
  120.   stop_ahi_sound (c);
  121.   c->AHIio->ahir_Std.io_Command = CMD_WRITE;
  122.   c->AHIio->ahir_Std.io_Flags = 0;
  123.   c->AHIio->ahir_Std.io_Message.mn_Node.ln_Pri = -50;   /* sound effects */
  124.   c->AHIio->ahir_Std.io_Data = buffer;
  125.   c->AHIio->ahir_Std.io_Length = length;
  126.   c->AHIio->ahir_Type = AHIST_S16S;
  127.   c->AHIio->ahir_Frequency = shm->speed;
  128.   c->AHIio->ahir_Volume = 0x10000;
  129.   c->AHIio->ahir_Position = 0x8000;
  130.   c->AHIio->ahir_Link = link;
  131.   SendIO ((struct IORequest *)c->AHIio);
  132.   c->sound_in_progress = TRUE;
  133. }
  134.  
  135. /**********************************************************************/
  136. // Stops an audio.device sound channel.
  137.  
  138. static void stopsound (int cnum)
  139. {
  140.   if (!audio_is_open)
  141.     return;
  142.   if (channel_info[cnum].sound_in_progress) {
  143.     AbortIO ((struct IORequest *)channel_info[cnum].audio_io);
  144.     WaitPort (channel_info[cnum].audio_mp);
  145.     GetMsg (channel_info[cnum].audio_mp);
  146.     channel_info[cnum].sound_in_progress = FALSE;
  147.   }
  148. }
  149.  
  150. /**********************************************************************/
  151. // Starts an audio.device sound in a particular sound channel.
  152.  
  153. static int startsound (int cnum, char *buffer, int length)
  154. {
  155.   struct channel_info *c;
  156.  
  157.   if (!audio_is_open)
  158.     return 1;
  159.   stopsound (cnum);
  160.   c = &channel_info[cnum];
  161.   c->audio_io->ioa_Request.io_Command = CMD_WRITE;
  162.   c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
  163.   c->audio_io->ioa_Data = buffer;
  164.   c->audio_io->ioa_Length = length;
  165.   c->audio_io->ioa_Period = period;
  166.   c->audio_io->ioa_Volume = 64;
  167.   c->audio_io->ioa_Cycles = 0;
  168.   BeginIO ((struct IORequest *)c->audio_io);
  169.   c->starttime = Sys_FloatTime ();
  170.   c->sound_in_progress = TRUE;
  171.   return cnum;
  172. }
  173.  
  174. /**********************************************************************/
  175.  
  176. qboolean SNDDMA_Init (void)
  177. {
  178.   int i, unit = 0;
  179.   struct channel_info *c;
  180.   UBYTE chans[1];
  181.  
  182. //  printf ("SNDDMA_Init()\n");
  183.  
  184.   if ((shm = (dma_t *)malloc (sizeof(dma_t))) == NULL)
  185.     Sys_Error ("malloc() failed");
  186.   memset((void*)shm, 0, sizeof(dma_t));
  187.  
  188.   if (COM_CheckParm ("-ahi")) {
  189.         if ((unit = COM_CheckParm ("-ahiunit"))) {
  190.             if (unit < com_argc-1)
  191.                 unit = Q_atoi (com_argv[unit+1]);
  192.             else
  193.                 Sys_Error ("You must specify a number after -unit");
  194.         }
  195.     Con_Printf("Using AHI unit %d.\n", unit);
  196.     using_ahi = TRUE;
  197.  
  198. //#if defined(__SASC) && defined(__PPC__)
  199. //    if ((shm->buffer = PPCAllocMem (AHIBUFFERSIZE, MEMF_NOCACHESYNCPPC |
  200. //                                MEMF_NOCACHESYNCM68K | MEMF_PUBLIC)) == NULL)
  201. //#else
  202.     if ((shm->buffer = malloc (AHIBUFFERSIZE)) == NULL)
  203. //#endif
  204.       Sys_Error ("malloc() failed");
  205.     memset (shm->buffer, 0, AHIBUFFERSIZE);
  206.  
  207.     shm->channels = 2;
  208.     shm->speed = desired_speed;
  209.     shm->samplebits = 16;
  210.     shm->samples = AHIBUFFERSIZE / (shm->samplebits / 8);
  211.     shm->submission_chunk = 1;
  212.  
  213.     if ((AHImp = CreateMsgPort ()) == NULL)
  214.       Sys_Error ("CreateMsgPort() failed");
  215.     for (i = 0; i < 2; i++)
  216.       if ((ahi_channel_info[i].AHIio = (struct AHIRequest *)CreateIORequest
  217.                                    (AHImp, sizeof(struct AHIRequest))) == NULL)
  218.         Sys_Error ("CreateIORequest() failed");
  219.     ahi_channel_info[0].AHIio->ahir_Version = 4;
  220.     if ((AHIDevice = OpenDevice (AHINAME, unit,
  221.                                  (struct IORequest *)ahi_channel_info[0].AHIio,
  222.                                  0)) != 0)
  223.       Sys_Error ("OpenDevice() failed");
  224.     ahidevice_is_open = TRUE;
  225.     AHIBase = (struct Library *)ahi_channel_info[0].AHIio->ahir_Std.io_Device;
  226.     *ahi_channel_info[1].AHIio = *ahi_channel_info[0].AHIio;
  227.  
  228.     twice_real_speed = 2.0 * (double)shm->speed;
  229.     ahi_playtime = ((double)(AHIBUFFERSIZE >> 2)) / (double)shm->speed;
  230.     //printf ("ahi_playtime = %f\n", ahi_playtime);
  231.  
  232.     ahi_channel_info[0].starttime = Sys_FloatTime ();
  233.     start_ahi_sound (&ahi_channel_info[0], shm->buffer, AHIBUFFERSIZE, NULL);
  234.     //printf ("start[0] = %f  %f\n", ahi_channel_info[0].starttime,
  235.     //                               ahi_channel_info[0].starttime + ahi_playtime);
  236.     ahi_channel_info[1].starttime = ahi_channel_info[0].starttime + ahi_playtime;
  237.     start_ahi_sound (&ahi_channel_info[1], shm->buffer, AHIBUFFERSIZE,
  238.                      ahi_channel_info[0].AHIio);
  239.     //printf ("start[1] = %f  %f\n", ahi_channel_info[1].starttime,
  240.     //                               ahi_channel_info[1].starttime + ahi_playtime);
  241.     which_buffer = 0;
  242.  
  243.   } else { /* audio.device */
  244.  
  245.     Con_Printf("Using audio.device.\n");
  246.     using_ahi = FALSE;
  247.  
  248.     if ((shm->buffer = AllocMem (BUFFERSIZE, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  249.       Sys_Error ("Out of CHIP memory for sound");
  250. //    memset(shm->buffer, 0x80, BUFFERSIZE);
  251.  
  252. //    printf ("Sound buffer at 0x%08x\n", shm->buffer);
  253.  
  254.     shm->channels = 2;
  255.     shm->speed = desired_speed;
  256.     shm->samplebits = 8;
  257.     shm->samples = BUFFERSIZE / (shm->samplebits / 8);
  258.     shm->submission_chunk = 1;
  259.  
  260.     if ((audio_mp = CreateMsgPort ()) == NULL ||
  261.         (audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
  262.                                              MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  263.       Sys_Error ("CreateMsgPort() or AllocMem() failed");
  264.  
  265.     chans[0] = (1 << shm->channels) - 1; /* shm->channels Amiga audio channels */
  266.     audio_io->ioa_Request.io_Message.mn_ReplyPort = audio_mp;
  267.     audio_io->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
  268.     audio_io->ioa_AllocKey = 0;
  269.     audio_io->ioa_Data = chans;
  270.     audio_io->ioa_Length = sizeof(chans);
  271.  
  272.     if (OpenDevice (AUDIONAME, 0, (struct IORequest *)audio_io, 0) != 0)
  273.       Sys_Error ("OpenDevice(\"audio.device\") failed");
  274.     audio_is_open = TRUE;
  275.  
  276.     for (i = 0; i < shm->channels; i++) {
  277.       c = &channel_info[i];
  278.       if ((c->audio_mp = CreateMsgPort ()) == NULL ||
  279.           (c->audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
  280.                                              MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  281.         Sys_Error ("CreateMsgPort() or AllocMem() failed");
  282.       *c->audio_io = *audio_io;
  283.       c->audio_io->ioa_Request.io_Message.mn_ReplyPort = c->audio_mp;
  284.       c->audio_io->ioa_Request.io_Unit = (struct Unit *)(1 << i);
  285.     }
  286.  
  287.     if ((GfxBase->DisplayFlags & REALLY_PAL) == 0)
  288.       clock_constant = 3579545;   /* NTSC */
  289.     else
  290.       clock_constant = 3546895;   /* PAL */
  291.  
  292.     period = ((clock_constant << 1) + shm->speed) / ((shm->speed) << 1);
  293.  
  294.     twice_real_speed = 2.0 * ((double)clock_constant) / (double)period;
  295.  
  296.     startsound (0, shm->buffer, BUFFERSIZE >> 1);
  297.     startsound (1, shm->buffer + (BUFFERSIZE >> 1), BUFFERSIZE >> 1);
  298.   }
  299.  
  300.   return 1;
  301. }
  302.  
  303. /**********************************************************************/
  304.  
  305. int SNDDMA_GetDMAPos (void)
  306. {
  307.   if (shm == NULL || shm->buffer == NULL)
  308.     return 0;
  309.  
  310.   if (using_ahi) {
  311.  
  312.     if (!ahi_channel_info[0].sound_in_progress)
  313.       shm->samplepos = 0;
  314.     else {
  315.       struct ahi_channel_info *c, *c2;
  316.       double now;
  317.  
  318.       now = Sys_FloatTime ();
  319.       c = &ahi_channel_info[which_buffer];
  320.       if (now >= c->starttime + ahi_playtime - 0.1 &&
  321.           CheckIO ((struct IORequest *)c->AHIio)) {
  322.         //printf ("finished[%d] = %f  %f\n", which_buffer, now,
  323.         //                                   now - (c->starttime + ahi_playtime));
  324.         c2 = &ahi_channel_info[1 - which_buffer];
  325.         if (c2->starttime > now) {
  326.           c2->starttime = now;
  327.           //printf ("changed[%d] = %f  %f\n", 1 - which_buffer, c2->starttime,
  328.           //                                  c2->starttime + ahi_playtime);
  329.         }
  330.         WaitPort (AHImp);
  331.         GetMsg (AHImp);
  332.         c->sound_in_progress = FALSE;
  333.         if ((now = Sys_FloatTime ()) > (c->starttime =
  334.                                         c2->starttime + ahi_playtime))
  335.           c->starttime = now;
  336.         start_ahi_sound (c, shm->buffer, AHIBUFFERSIZE,
  337.                          ahi_channel_info[1 - which_buffer].AHIio);
  338.         //printf ("start[%d] = %f  %f\n", which_buffer, c->starttime,
  339.         //                                c->starttime + ahi_playtime);
  340.         which_buffer = 1 - which_buffer;
  341.         c = &ahi_channel_info[which_buffer];
  342.       }
  343.       shm->samplepos = ((int)((now + ahi_playtime - c->starttime) *
  344.                               twice_real_speed + 0.5)) & (AHIBUFFERSIZE - 1);
  345.     }
  346.  
  347.   } else {  /* audio.device */
  348.  
  349.     if (!channel_info[0].sound_in_progress)
  350.       shm->samplepos = 0;
  351.     else
  352.       shm->samplepos = ((int)((Sys_FloatTime() - channel_info[0].starttime)
  353.                               * twice_real_speed + 0.5))
  354.                        & (BUFFERSIZE - 1);
  355.  
  356.   }
  357.  
  358.   return shm->samplepos;
  359. }
  360.  
  361. /**********************************************************************/
  362.  
  363. void SNDDMA_Shutdown (void)
  364. {
  365.   int i;
  366.  
  367. //  printf ("SNDDMA_Shutdown()\n");
  368.  
  369.   for (i = 0; i < 2; i++)
  370.     stop_ahi_sound (&ahi_channel_info[i]);
  371.   if (ahidevice_is_open) {
  372.     CloseDevice ((struct IORequest *)ahi_channel_info[0].AHIio);
  373.     ahidevice_is_open = FALSE;
  374.   }
  375.   for (i = 0; i < 2; i++) {
  376.     if (ahi_channel_info[i].AHIio != NULL) {
  377.       DeleteIORequest ((struct IORequest *)ahi_channel_info[i].AHIio);
  378.       ahi_channel_info[i].AHIio = NULL;
  379.     }
  380.   }
  381.   if (AHImp != NULL) {
  382.     DeleteMsgPort (AHImp);
  383.     AHImp = NULL;
  384.   }
  385.   if (audio_is_open) {
  386.     if (shm != NULL) {
  387.       for (i = 0; i < shm->channels; i++)
  388.         stopsound (i);
  389.       audio_io->ioa_Request.io_Unit = (struct Unit *)
  390.                        ((1 << shm->channels) - 1);  /* free shm->channels channels */
  391.     }
  392.     CloseDevice ((struct IORequest *)audio_io);
  393.     audio_is_open = FALSE;
  394.   }
  395.   for (i = 0; i < MAXNUMCHANNELS; i++) {
  396.     if (channel_info[i].audio_io != NULL) {
  397.       FreeMem (channel_info[i].audio_io, sizeof(struct IOAudio));
  398.       channel_info[i].audio_io = NULL;
  399.     }
  400.     if (channel_info[i].audio_mp != NULL) {
  401.       DeleteMsgPort (channel_info[i].audio_mp);
  402.       channel_info[i].audio_mp = NULL;
  403.     }
  404.   }
  405.   if (audio_io != NULL) {
  406.     FreeMem (audio_io, sizeof(struct IOAudio));
  407.     audio_io = NULL;
  408.   }
  409.   if (audio_mp != NULL) {
  410.     DeleteMsgPort (audio_mp);
  411.     audio_mp = NULL;
  412.   }
  413.   if (shm != NULL) {
  414.     if (shm->buffer != NULL) {
  415.       if (using_ahi)
  416. //#if defined(__SASC) && defined(__PPC__)
  417. //        PPCFreeMem (shm->buffer, AHIBUFFERSIZE);
  418. //#else
  419.         free (shm->buffer);
  420. //#endif
  421.       else
  422.         FreeMem (shm->buffer, BUFFERSIZE);
  423.       shm->buffer = NULL;
  424.     }
  425.     free ((char *)shm);
  426.     shm = NULL;
  427.   }
  428. }
  429.  
  430. /**********************************************************************/
  431. void SNDDMA_Submit (void)
  432. {
  433. //  printf ("SNDDMA_Submit()\n");
  434. }
  435.  
  436. /**********************************************************************/
  437.